package com.hkts.naturalgasauthentication.security.jwt;

import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import com.hkts.naturalgasauthentication.base.entity.User;
import com.hkts.naturalgasauthentication.base.service.HontUserService;
import com.hkts.naturalgasauthentication.common.SecurityConstant;
import com.hkts.naturalgasauthentication.common.annotation.SystemLog;
import com.hkts.naturalgasauthentication.common.enums.LogType;
import com.hkts.naturalgasauthentication.common.getopenid.Getid;
import com.hkts.naturalgasauthentication.common.vo.TokenUser;
import com.hkts.naturalgasauthentication.config.properties.ManagementTokenProperties;
import com.hkts.naturalgasauthentication.utils.IpInfoUtil;
import com.hkts.naturalgasauthentication.utils.ResponseUtil;
import com.hkts.naturalgasauthentication.utils.SecurityUtil;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    @Autowired
    private IpInfoUtil ipInfoUtil;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ManagementTokenProperties tokenProperties;
    @Autowired
    private HontUserService hontUserService;
    @Autowired
    private SecurityUtil securityUtil;

    @SneakyThrows
    @Override
    @SystemLog(description = "登录系统", type = LogType.LOGIN)
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        //
        String type = request.getParameter("type");
        String username = ((UserDetails) authentication.getPrincipal()).getUsername();

        //用户选择保存登录状态几天
        String saveLogin = request.getParameter(SecurityConstant.SAVE_LOGIN);
        String code = request.getParameter("code");
        Boolean saved = false;
        if (StrUtil.isNotBlank(saveLogin) && Boolean.valueOf(saveLogin)) {
            saved = true;
            if (!tokenProperties.getRedis()) {
                tokenProperties.setTokenExpireTime(tokenProperties.getSaveLoginTime() * 60 * 24);
            }
        }
        //当在pc端登录时需要确认该用户是否为管理员
       if(StringUtils.isNotBlank(type)&&type.equals("1")){
           User currUser = securityUtil.getCurrUser();
           if(!currUser.getType().equals(Integer.valueOf(type))){
               Map<String, Object> resultMap = new HashMap<String, Object>(16);
               resultMap.put("error", false);
               resultMap.put("message", "当前用户不存在！");
               resultMap.put("code", 500);
               resultMap.put("result", "error！");
               ResponseUtil.out(response, resultMap);
               return;
           }
       }
        List<GrantedAuthority> authorities = (List<GrantedAuthority>) ((UserDetails) authentication.getPrincipal()).getAuthorities();
        List<String> list = new ArrayList<>();

        // 登陆成功生成token
        String token;
        if (tokenProperties.getRedis()) {
            // redis
            token = UUID.randomUUID().toString().replace("-", "");
            TokenUser user = new TokenUser(username, list, saved);
            // 不缓存权限
            if (!tokenProperties.getStorePerms()) {
                user.setPermissions(null);
            }
            // 单设备登录 之前的token失效
            if (tokenProperties.getSdl()) {
              /*  String oldToken = redisTemplate.opsForValue().get(SecurityConstant.USER_TOKEN + username);
                if (StrUtil.isNotBlank(oldToken)) {
                    redisTemplate.delete(SecurityConstant.TOKEN_PRE + oldToken);
                }*/
                //重新
                if(StringUtils.isNotBlank(type)){
                    String s = redisTemplate.opsForValue().get(SecurityConstant.TOKEN_TYPE + username + ":" + type);
                    if(StringUtils.isNotBlank(s)){
                        redisTemplate.delete(SecurityConstant.TOKEN_PRE + s);
                    }
                }else{
                    String s = redisTemplate.opsForValue().get(SecurityConstant.TOKEN_TYPE + username );
                    if(StringUtils.isNotBlank(s)){
                        redisTemplate.delete(SecurityConstant.TOKEN_PRE + s);
                    }
                }
            }
            //token 有效时间7天
            redisTemplate.opsForValue().set(SecurityConstant.USER_TOKEN + username, token, tokenProperties.getSaveLoginTime(), TimeUnit.DAYS);
            redisTemplate.opsForValue().set(SecurityConstant.TOKEN_PRE + token, new Gson().toJson(user), tokenProperties.getSaveLoginTime(), TimeUnit.DAYS);
            if(StringUtils.isNotBlank(type)){
                redisTemplate.opsForValue().set(SecurityConstant.TOKEN_TYPE+username+":"+type, token);
            }else{
                redisTemplate.opsForValue().set(SecurityConstant.TOKEN_TYPE+username,token);
            }
            //保持等录功能暂时取消
           /* if(saved){
                redisTemplate.opsForValue().set(SecurityConstant.USER_TOKEN + username, token, tokenProperties.getSaveLoginTime(), TimeUnit.DAYS);
                redisTemplate.opsForValue().set(SecurityConstant.TOKEN_PRE + token, new Gson().toJson(user), tokenProperties.getSaveLoginTime(), TimeUnit.DAYS);
            }else{
                redisTemplate.opsForValue().set(SecurityConstant.USER_TOKEN + username, token, tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
                redisTemplate.opsForValue().set(SecurityConstant.TOKEN_PRE + token, new Gson().toJson(user), tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
            }*/
        } else {
            // 不缓存权限
            if (!tokenProperties.getStorePerms()) {
                list = null;
            }
            // jwt
            token = SecurityConstant.TOKEN_SPLIT + Jwts.builder()
                    //主题 放入用户名
                    .setSubject(username)
                    //自定义属性 放入用户拥有请求权限
                    .claim(SecurityConstant.AUTHORITIES, new Gson().toJson(list))
                    //失效时间
                    .setExpiration(new Date(System.currentTimeMillis() + tokenProperties.getTokenExpireTime() * 60 * 1000))
                    //签名算法和密钥
                    .signWith(SignatureAlgorithm.HS512, SecurityConstant.JWT_SIGN_KEY)
                    .compact();
        }
        Map<String, Object> resultMap = new HashMap<String, Object>(16);
        resultMap.put("success", true);
        resultMap.put("message", "登陆成功!");
        resultMap.put("code", 200);
        resultMap.put("timestamp", System.currentTimeMillis());
        resultMap.put("token", token);
        resultMap.put("result", token);
        ResponseUtil.out(response, resultMap);
        User user = (User) authentication.getPrincipal();

        String openid = Getid.getUserInfo(code);
        if (StringUtils.isBlank(openid)) {
            resultMap.put("error", false);
            resultMap.put("message", "error");
            resultMap.put("code", 500);
            resultMap.put("result", "openid未获取！");
            ResponseUtil.out(response, resultMap);
        }else if(StringUtils.isBlank(user.getOpenId())||!user.getOpenId().equals(openid)){
            user.setOpenId(openid);
            hontUserService.updateOpenId(user);
        }
    }
}
